#include "utils.h"
#include "time.h"
#include "uuid/uuid.h"
static struct timeval _tmStart;
static struct timeval _tmStop;

Utils::Utils(){}

std::string Utils::createUUID()
{
    uuid_t uuid1;
    char uuid1_str[37]={0};
    uuid_generate(uuid1);
    uuid_unparse(uuid1, uuid1_str);
    return uuid1_str;
}

void Utils::startTick()
{
    memset(&_tmStart,0,sizeof(_tmStart));
    gettimeofday(&_tmStart,0);
}

double Utils::stopTick()
{
    gettimeofday(&_tmStop,0);
    return (_tmStop.tv_sec - _tmStart.tv_sec) + (double)(_tmStop.tv_usec - _tmStart.tv_usec) / 1000000.0;
}

std::string Utils::getCurrentData()
{
    time_t now = time(0);
    tm* ltm = localtime(&now);

    char year[8] = {0};
    char month[8] = {0};
    char day[8] = {0};
    sprintf(year,"%d",ltm->tm_year + 1900);
    sprintf(month,"%d",ltm->tm_mon + 1);
    sprintf(day,"%d",ltm->tm_mday);
    std::string str;
    str += year;
    str += "-";
    str += month;
    str += "-";
    str += day;
    return str;
}

std::string Utils::getCurrentTime()
{
    time_t now = time(0);
    tm* ltm = localtime(&now);

    char hour[8] = {0};
    char minute[8] = {0};
    char second[8] = {0};
    sprintf(hour,"%d",ltm->tm_hour);
    sprintf(minute,"%d",ltm->tm_min);
    sprintf(second,"%d",ltm->tm_sec);
    std::string str;
    str += hour;
    str += ":";
    str += minute;
    str += ":";
    str += second;
    return str;
}

std::string Utils::getCurrentDateTime()
{
    time_t now = time(0);
    tm* ltm = localtime(&now);

    char year[8] = {0};
    char month[8] = {0};
    char day[8] = {0};
    char hour[8] = {0};
    char minute[8] = {0};
    char second[8] = {0};
    sprintf(year,"%d",ltm->tm_year + 1900);
    sprintf(month,"%d",ltm->tm_mon + 1);
    sprintf(day,"%d",ltm->tm_mday);
    sprintf(hour,"%d",ltm->tm_hour);
    sprintf(minute,"%d",ltm->tm_min);
    sprintf(second,"%d",ltm->tm_sec);
    std::string str;
    str += year;
    str += "-";
    str += month;
    str += "-";
    str += day;
    str += " ";
    str += hour;
    str += ":";
    str += minute;
    str += ":";
    str += second;
    return str;
}

unsigned long Utils::getTotalSecondScenceEporch()
{
    struct timeval tm;
    gettimeofday(&tm,0);
    return  tm.tv_sec;
}

void Utils::trimString(std::string &src)
{
    size_t len = src.length();
    char* sz = new char[len +1];
    memcpy(sz,src.c_str(),len);
    sz[len] = '\0';
    for(size_t i = len -1 ; i >= 0; --i)
    {
        if(sz[i] == ' ' || sz[i] == '\t')
        {
            sz[i] = '\0';
        }
        else
        {
            break;
        }
    }
    char* pos = nullptr;
    for(size_t i = 0 ; i < len; ++i)
    {
        if(sz[i] == ' ' || sz[i] == '\t')
        {
            continue;
        }
        else
        {
            pos = sz + i;
            break;
        }
    }
    src = pos;
    delete[] sz;
}

int Utils::getSubStringCount(const std::string &src, const std::string &sep)
{
    int cnt = 0;
    std::string::size_type index = src.find(sep, 0);
    while(index != std::string::npos)
    {
        ++cnt;
        index = src.find(sep, index + sep.size());
    }
    return cnt;
}

void Utils::splitString(const std::string &src, const std::string &sep, std::vector<std::string> &result)
{
    result.clear();
    result.reserve(getSubStringCount(src, sep) + 1);
    std::string::size_type start = 0;
    std::string::size_type index = src.find(sep, start);
    while(index != std::string::npos)
    {
        result.push_back(src.substr(start, index - start));
        start = index + sep.size();
        index = src.find(sep, start);
    }
    result.push_back(src.substr(start));
}

void Utils::lowerCaseString(const std::string &src, std::string &result)
{
    result = src;
    std::transform(src.begin(), src.end(),
                   result.begin(),
                   [](unsigned char c) -> unsigned char {
        return std::tolower (c);
    } );
}

void Utils::upperCaseString(const std::string &src, std::string &result)
{
    result = src;
    std::transform(src.begin(), src.end(),
                   result.begin(),
                   [](unsigned char c) -> unsigned char {
        return std::toupper (c);
    } );
}

void Utils::replaceString(std::string &src, const std::string &_olds, const std::string &_news, int count)
{
    std::string::size_type index = src.find(_olds);
    while(index != std::string::npos && count)
    {
        src.replace(index, _olds.size(), _news);
        index = src.find(_olds);
        count = count > 0 ? count - 1 : count;
    }
}

bool Utils::startWithString(const std::string &src, const std::string &head)
{
    return head.size() <= src.size()
            && src.compare(0, head.size(), head) == 0;
}

bool Utils::endWithString(const std::string &src, const std::string &tail)
{
    return tail.size() <= src.size()
            && src.compare(src.size() - tail.size(), tail.size(), tail) == 0;
}

void Utils::getMacIP(std::vector<std::string> &_devNameList, std::vector<std::string> &_macList, std::vector<std::string> &_ipList)
{
    int fd;
    int interfaceNum = 0;
    struct ifreq buf[16];
    struct ifconf ifc;
    struct ifreq ifrcopy;
    char mac[64] = {0};
    char ip[64] = {0};
    char broadAddr[32] = {0};
    char subnetMask[32] = {0};

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");

        close(fd);
        return;
    }

    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t)buf;
    if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc))
    {
        interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
        while (interfaceNum-- > 0)
        {
            _devNameList.push_back(buf[interfaceNum].ifr_name);

            ifrcopy = buf[interfaceNum];
            if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy))
            {
                close(fd);
                return;
            }

            //get the mac of this interface
            if (!ioctl(fd, SIOCGIFHWADDR, (char *)(&buf[interfaceNum])))
            {
                memset(mac, 0, sizeof(mac));
                snprintf(mac, sizeof(mac), "%02X-%02X-%02X-%02X-%02X-%02X",
                         (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[0],
                        (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[1],
                        (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[2],

                        (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[3],
                        (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[4],
                        (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[5]);
                _macList.push_back(mac);
                memset(mac,0,sizeof(mac));
            }
            else
            {
                close(fd);
                return;
            }

            //get the IP of this interface

            if (!ioctl(fd, SIOCGIFADDR, (char *)&buf[interfaceNum]))
            {
                snprintf(ip, sizeof(ip), "%s",
                         (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_addr))->sin_addr));
                _ipList.push_back(ip);
                memset(ip,0,sizeof(ip));
            }
            else
            {
                close(fd);
                return;
            }

            //get the broad address of this interface

            if (!ioctl(fd, SIOCGIFBRDADDR, &buf[interfaceNum]))
            {
                snprintf(broadAddr, sizeof(broadAddr), "%s",
                         (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_broadaddr))->sin_addr));
            }
            else
            {
                close(fd);
                return;
            }

            //get the subnet mask of this interface
            if (!ioctl(fd, SIOCGIFNETMASK, &buf[interfaceNum]))
            {
                snprintf(subnetMask, sizeof(subnetMask), "%s",
                         (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_netmask))->sin_addr));
            }
            else
            {
                close(fd);
                return;

            }
        }
    }
    else
    {
        close(fd);
        return;
    }

    close(fd);

    return;
}

bool Utils::create_cert(std::string file)
{
    if(file.empty())
        return false;
    if(FileOperate::isFileExist(file))
        return true;
    std::ofstream ofs(file.c_str());
    if(ofs.is_open())
    {
        std::vector<std::string> devnamelist;
        std::vector<std::string> maclist;
        std::vector<std::string> iplist;
        getMacIP(devnamelist,maclist,iplist);

        time_t _time = time(nullptr);
        std::stringstream ss;
        ss << _time;
        std::string str;
        ss >> str;
        for(auto iter = devnamelist.begin(); iter != devnamelist.end(); ++iter)
        {
            str += *iter;
        }
        for(auto iter = maclist.begin(); iter != maclist.end(); ++iter)
        {
            str += *iter;
        }
        for(auto iter = iplist.begin(); iter != iplist.end(); ++iter)
        {
            str += *iter;
        }
        std::string destStr;
        Encrypt::SM4_EncryptionString(str,destStr);
        ofs << destStr;
        ofs.close();
        return true;
    }
    return false;
}

bool Utils::check_cert(std::string file)
{
    std::string str1 = FileOperate::readFileText(file);
    if(str1.empty()) return false;
    std::string str2;
    Encrypt::SM4_DecryptString(str1,str2);

    std::vector<std::string> devnamelist;
    std::vector<std::string> maclist;
    std::vector<std::string> iplist;
    getMacIP(devnamelist,maclist,iplist);

    std::string str;
    for(auto iter = devnamelist.begin(); iter != devnamelist.end(); ++iter)
    {
        str += *iter;
    }
    for(auto iter = maclist.begin(); iter != maclist.end(); ++iter)
    {
        str += *iter;
    }
    for(auto iter = iplist.begin(); iter != iplist.end(); ++iter)
    {
        str += *iter;
    }

    if(Utils::endWithString(str2,str))
    {
        return true;
    }
    return false;
}

bool Utils::create_license(const std::string file_cert, std::string file_license)
{
    std::string str1 = FileOperate::readFileText(file_cert);
    if(str1.empty()) return false;
    std::string str2;
    Encrypt::SM4_EncryptionString(str1,str2);
    FileOperate::writeFileText(str2,file_license);
    return true;
}

bool Utils::check_license(std::string file_cert, std::string file_license)
{
    bool flag = false;
    if(!FileOperate::isFileExist(file_cert))
    {
        return false;
    }

    std::string str1 = FileOperate::readFileText(file_cert);
    std::string str2 = FileOperate::readFileText(file_license);

    std::string dst1;
    Encrypt::SM4_DecryptString(str2,dst1);

    if(dst1 == str1)
    {
        flag = true;
    }

    return flag;
}
